"""
    Contains Container and ModelObjectContainer classes.
"""

import cherrypy
import turbogears
from turbogears import controllers
from mnemoply.utils import isint

class Container(controllers.Controller):
    """
        Provide Restful-style access to database objects.
    """

    search_in_object = False

    def __init__(self):
        controllers.Controller.__init__(self)

        self.facets = []

    @turbogears.expose()
    def default(self, *vpath, **params):
        """Do RESTful-style access to database objects. Based on
        the RESTful resource recipe by Robert Brewer."""

        # We saw is last atom in path is number without slash
        if isint(cherrypy.request.path.split('/')[-1]):
            raise turbogears.redirect(cherrypy.request.path + "/")

        if not vpath:
            return self.index(**params)
        # Make a copy of vpath in a list
        vpath = list(vpath)
        atom = vpath.pop(0)

        # See if the first virtual path member is a container action
        method = getattr(self, atom, None)
        if method and not getattr(method, "expose_object", False):
            if not getattr(method, "expose", False):
                raise cherrypy.NotFound
            return method(*vpath, **params)

        # Not a container action; the URI atom must be an existing ID
        item = self._get_item(atom)
        if item is None:
            raise cherrypy.NotFound

        # Got item controller
        if isinstance(item, (tuple, list)):
            (item, controller) = item

            if vpath:
                name = vpath[0]

                method = getattr(controller, name, None)
                if method and getattr(method, "exposed", False):
                    return method(item, *vpath[1:], **params)

            return controller.show(item, *vpath, **params)

        # There may be further virtual path components.
        # Try to map them to methods in this class.
        if vpath:
            name = vpath[0]

            # Search in container
            method = getattr(self, name, None)
            if method and getattr(method, "exposed", False):
                if getattr(method, "expose_object", False):
                    return method(item, *vpath[1:], **params)

            # Search in item
            method = getattr(item, name, None)
            if method and getattr(method, "exposed", False):
                try:
                    return method(item, *vpath[1:], **params)
                # If method has been called without arguments we raise 404.
                # For example: 'pay_confirm() takes at least 3 arguments (2 given)'
                except TypeError:
                    raise cherrypy.NotFound

            # Search in facets
            for facet in self.facets:
                method = getattr(facet, name, None)
                if method and getattr(method, "exposed", False):
                    return method(item, *vpath[1:], **params)

        # No further known vpath components. Call a default handler.
        return self.show(item, *vpath, **params)

class ModelObjectContainer(Container):
    """
        Container inheritor where _get_item returns object from database.
    """

    def __init__(self, model_object):
        Container.__init__(self)
        self.model_object = model_object

    def _get_item(self, key):
        try:
            return self.model_object.get(int(key))
        except LookupError:
            return None
        except ValueError:
            return None
